import type { YmColProps } from 'ym-design';
import type {
  FieldCombineEntity,
  FieldData,
  InternalFieldData,
  Meta,
} from './FieldEntityType';
import type { Rule, ValidateMessages, ValidateOptions } from './ValidateType';

export type StoreValue = any;
export type Store = Record<string, StoreValue>;
export type NamePath = string | number | (string | number)[];
export type InternalNamePath = (string | number)[];

export type RecursivePartial<T> = NonNullable<T> extends object
  ? {
      [P in keyof T]?: T[P];
    }
  : T;

export interface ValidateErrorEntity<Values = any> {
  values: Values;
  errorFields: { name: InternalNamePath; errors: string[] }[];
}

export interface Callbacks<Values = any> {
  onValuesChange?: (
    changedValues: RecursivePartial<Values>,
    values: Values,
  ) => void;
  onFieldsChange?: (changedFields: FieldData[], allFields: FieldData[]) => void;
  onFinish?: (values: Values) => void;
  onFinishFailed?: (errorInfo: ValidateErrorEntity<Values>) => void;
}

export interface FormInstance<Values = any> {
  getFieldValue: (name: NamePath) => StoreValue;
  getFieldsValue: (
    nameList?: NamePath[] | 'default' | 'all' | 'asFormListItem',
  ) => any;
  setFieldValue: (name: NamePath, value: StoreValue) => void;
  setFieldsValue: (values: RecursivePartial<Values>) => void;
  setFields: (fields: FieldData[]) => void;
  resetFields: (nameList?: NamePath[]) => void;
  validateFields: (
    nameList?: NamePath[],
    validateConfig?: ValidateOptions,
  ) => Promise<Values>;
  submit: () => void;
}
export type SizeType = 'small' | 'middle' | 'large' | undefined;
export type FormLabelAlign = 'left' | 'right';

type BaseFormProps = Omit<
  React.FormHTMLAttributes<HTMLFormElement>,
  'onSubmit' | 'onRest'
>;
export type FormLayout = 'horizontal' | 'inline' | 'vertical';

export interface YmFormLayoutProps {
  prefixCls?: string;
  layout?: FormLayout;
  name?: string;
  colon?: boolean;
  labelAlign: FormLabelAlign;
  labelWrap?: boolean;
  labelCol?: YmColProps;
  wrapperCol?: YmColProps;
  disabled?: boolean;
  size?: SizeType;
}

export interface YmFormProps<Values = any>
  extends BaseFormProps, //BaseFormProps已包含 className
    Partial<YmFormLayoutProps> {
  // className?: string;
  // scrollToFirstError?: boolean; 未完成
  form?: FormInstance<Values>;
  initialValues?: RecursivePartial<Values>;
  children: React.ReactNode;
  fields?: FieldData[];
  validateTrigger?: string | string[];
  validateMessages?: ValidateMessages;
  component?: boolean; // 是否渲染 form 标签
  onFinish?: Callbacks<Values>['onFinish'];
  onFinishFailed?: Callbacks<Values>['onFinishFailed'];
  onFieldsChange?: Callbacks<Values>['onFieldsChange'];
  onValuesChange?: Callbacks<Values>['onValuesChange'];
}

// export interface InternalValidateOptions extends ValidateOptions {
//   triggerName?: string;
//   validateMessages?: ValidateMessages;
// }

// export type InternalValidateFields<Values = any> = {
//   (options?: InternalValidateOptions): Promise<Values>;
//   (nameList?: NamePath[], options?: InternalValidateOptions): Promise<Values>;
// };

export interface InternalHooks {
  updateValue: (namePath: InternalNamePath, newValue: StoreValue) => void;
  initEntityValue: (entity: FieldCombineEntity) => void;
  registerField: (entity: FieldCombineEntity) => void;
  cancelField: (entity: FieldCombineEntity) => void;
  setInitialValues: (values: Store, init: boolean) => void;
  destroyForm: () => void;
  setCallbacks: (callbacks: Callbacks) => void;
  // registerWatch: (callback: WatchCallBack) => () => void;
  getFields: (namePathList?: InternalNamePath[]) => InternalFieldData[];
  setValidateMessages: (validateMessages: ValidateMessages) => void;
  getInitialValue: (namePath?: InternalNamePath) => StoreValue;
}

export interface InternalFormInstance extends FormInstance {
  /**
   * Form component should register some content into store.
   * We pass the `HOOK_MARK` as key to avoid user call the function.
   */
  getInternalHooks: (secret: string) => InternalHooks | null;
  prefixName?: InternalNamePath;
}

export interface ListField {
  name: number;
  key: number;
  isListField: boolean;
}

export interface ListOperations {
  add: (defaultValue?: StoreValue, index?: number) => void;
  remove: (index: number | number[]) => void;
  move: (from: number, to: number) => void;
}

export interface ListProps<Values = any> {
  name: NamePath;
  initialValue?: RecursivePartial<Values>[];
  rules?: Rule[];
  children: (
    fields: ListField[],
    operations: ListOperations,
    meta: Meta,
  ) => React.ReactNode;
  validateTrigger?: string | string[];
  isListField?: boolean;
}
